interface Button {
  btntype: string
  text: string
}
interface Link {
  alt: string
  href: string
}
interface Href {
  linktype: string
  target: Openlocation
}
enum Openlocation {
  self = 0,
  _blank,
  parent,
}
let button: Button = {
  btntype: 'normal',
  text: '跳转到百度',
}
let link: Link = {
  alt: 'goto baidu',
  href: 'http://www.baidu.com',
}
let href: Href = {
  linktype: '外网',
  target: Openlocation._blank,
}

/**
 * 参数 是类的对象 || 对象  || 是type的对象 || 接口的对象
 */
function cross<T extends object, U extends object>(
  objOne: T,
  objTwo: U
): T & U {
  /** 这里为什么要空对象，因为其他对象类型无法保证传过来的是一致的而且能够类型断言
   *  因为要把空对象断言成交叉类型之后才可以把值放空对象里面 所以要定义空对象类型
   */
  let obj = {}
  let combine = obj as T & U // 断言成 T 和 U  只允许添加 T 或 U 的属性 空对象可以像任何对象断言
  Object.keys(objOne).forEach((key) => {
    combine[key] = objOne[key]
  })
  Object.keys(objTwo).forEach((key) => {
    if (!obj.hasOwnProperty(key)) {
      combine[key] = objTwo[key]
    }
  })
  return combine
}

let combine = cross(button, link)
let combine2 = cross(combine, href)

console.log(combine);
console.log(combine2);
export {}
